#define _POSIX_SOURCE 1

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <sys/signal.h>
#include <unistd.h>
#include <fcntl.h>
#include <ctype.h>
#include <time.h>
#include <sys/time.h>

#include <opencv/cv.h>
#include <opencv/highgui.h>

// capture size.
#define CAP_WIDTH	320
#define CAP_HEIGHT	240

// grobal variable definition.
int fd;		// file descriptor.
struct termios oldTermIo;	// for keep now setting.

// prototype.
int Serial_Open(char *serialDev);
void Serial_Close(void);
int Serial_PutChar(unsigned char c);
int Serial_PutString(char *s);
unsigned char Serial_GetChar(void);

int main(int argc, char *argv[])
{
	char rBuffer[1024];
	char sBuffer[256];
	char *serialDev = "/dev/ttyUSB0";
	char c;

	CvCapture *capture = 0;
	IplImage *frame = 0;

	// create capture.
	capture = cvCreateCameraCapture(0);

	// capture size.
	cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, CAP_WIDTH);
	cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, CAP_HEIGHT);

	// clear buffer.
	memset(rBuffer, '\0', 1024);
	memset(sBuffer, '\0', 256);

	// open serial port.
	Serial_Open(serialDev);
	sleep(1);

	// create window.
	cvNamedWindow("Sniper Rifle", CV_WINDOW_AUTOSIZE);

	// initialize.
	Serial_PutString("@CPSM\n");

	while(1)
	{
		// capture and show.
		frame = cvQueryFrame(capture);
		cvShowImage("Sniper Rifle", frame);

		c = cvWaitKey(50);
		if (c == 27)
			break;		// ESC
		switch (c)
		{
		case 82:	// ^
			Serial_PutString("UP-60\n");
			break;
		case 84:	// v
			Serial_PutString("DOWN-60\n");
			break;
		case 81:	// <
			Serial_PutString("LEFT-90\n");
			break;
		case 83:	// >
			Serial_PutString("RIGHT-90\n");
			break;
		case 32:	// space
			Serial_PutString("FIRE-2580\n");
			break;
		default:
			break;
		}
	}

	// dispose OpenCV.
	cvReleaseCapture(&capture);
	cvDestroyWindow("Sniper Rifle");

	// close serial port.
	Serial_Close();

	return 0;
}

int Serial_Open(char *serialDev)
{
	struct termios newTermIo;

	// open device.
	fd = open(serialDev, O_RDWR | O_NOCTTY);
	if (fd < 0)
	{
		perror(serialDev);
		exit(-1);
	}

	// keep old setting.
	tcgetattr(fd, &oldTermIo);

	// new setting.
	newTermIo.c_iflag = 0;
	newTermIo.c_oflag = 0;
	newTermIo.c_cflag = 0;
	newTermIo.c_lflag = 0;
	newTermIo.c_line = 0;
	memset(newTermIo.c_cc, '\0', sizeof(newTermIo.c_cc));
	//bzero(newTermIo.c_cc, sizeof(newTermIo.c_cc));

	// 9600bps, 8bit, no parity, 1 stop bit, local, read enable
	newTermIo.c_cflag = B9600 | CS8 | CLOCAL | CREAD;
	// ignore parity error.
	newTermIo.c_iflag = IGNPAR;
	// raw mode.
	newTermIo.c_oflag = 0;
	// non-canonical, no echo
	newTermIo.c_lflag = 0;
	// inter-character timer
	newTermIo.c_cc[VTIME] = 0;
	newTermIo.c_cc[VMIN] = 1;

	// clear line.
	tcflush(fd, TCIFLUSH);

	// set.
	tcsetattr(fd, TCSANOW, &newTermIo);

	return (0);
}

void Serial_Close(void)
{
	tcsetattr(fd, TCSANOW, &oldTermIo);
	close(fd);
}

int Serial_PutChar(unsigned char c)
{
	if (write(fd, &c, 1) != 1)
		return (-1);

	return (0);
}

int Serial_PutString(char *s)
{
	if (write(fd, s, strlen(s)) <= 0)
		return (-1);

	return (0);
}

unsigned char Serial_GetChar(void)
{
	unsigned char c;
	
	read(fd, (char *)&c, 1);

	return (c);
}